#include "testApp.h"


//--------------------------------------------------------------
void testApp::setup(){
    //basic parameters
    height = 240;
    width = 320;

    //variables
    size = 20;
    value = 6;
    threshold = 25;
    blur = 20;

    verdana.loadFont("verdana.ttf", 8);

	bLearnBakground = false;

	vidGrabber.setVerbose(true);
    vidGrabber.initGrabber(width,height);

    colorImg.allocate(width,height);
	grayImage.allocate(width,height);
	grayBg.allocate(width,height);
	grayDiff.allocate(width,height);

}

//--------------------------------------------------------------
void testApp::update(){
	ofBackground(100,100,100);

    bool bNewFrame = false;

   vidGrabber.grabFrame();
   bNewFrame = vidGrabber.isFrameNew();

	if (bNewFrame){

        colorImg.setFromPixels(vidGrabber.getPixels(), width,height);

        grayImage = colorImg;
		if (bLearnBakground == true){
			grayBg = grayImage;		// the = sign copys the pixels from grayImage into grayBg (operator overloading)
			bLearnBakground = false;
		}

		// take the abs value of the difference between background and incoming and then threshold:
		grayDiff.absDiff(grayBg, grayImage);

		//grayDiff.contrastStretch();

		//blurs to remove noise
		grayDiff.blur(blur);
		//duotone threshold
		grayDiff.threshold(threshold);
		//threshold to create a line figure for easier contours
		grayDiff.adaptiveThreshold(10,15,true,false);

		// find contours which are between the size of 20 pixels and 1/3 the w*h pixels.
		// also, find holes is set to true so we will get interior contours as well....
		//contourFinder.findContours(grayDiff, 400, 2400, 3, true, true);	// find holes
		//values: source image, minimum size, max size, ammount of blogs, holes, **
	}

	if (clickTimer < 100) {clickTimer++;}
}

//--------------------------------------------------------------
void testApp::draw(){
	// draw the incoming, the grayscale, the bg and the thresholded difference in small thumbnails
	ofSetColor(0xffffff);
	grayImage.draw(205,10+height, width/5, height/5);
	grayBg.draw(210+width/5,10+height, width/5, height/5);
	//draws the active field
	grayDiff.draw(0,0);

    //makes an array of the active field booleans
    unsigned char * pixels = grayDiff.getPixels();
    //int green = pixels[(20 * widthOfLine) + 100 * 3 + 1];
    //int blue = pixels[(20 * widthOfLine) + 100 * 3 + 2];
    ofFill();
    ofSetColor(0xFF00FF);

    //checks activity of hand
    active = false;
    for (int x = width/4; x < width/4 + 20;x+=1) {
        for (int y = height/4; y < height/4 + 30;y+=1) {
            int degreesMade = 0;
            if (pixels[(y*width) + x] == NULL) {    //if the selected pixel contains NULL
                for (int a=0;a < 360; a+=30) {
                    //these formulas create a circle around the selected pixel and check their positions
                    int newX = cos(a) * size;
                    int newY = sin(a) * size;
                    if (pixels[((y+newY)*width) + x + newX] != NULL) {
                        //for every pixel in this circle that has an outline, degreesMade gets higher
                        degreesMade++;
                    }
                }
                if (degreesMade >= value/2) {
                    //when degreesMade gets high enough, a circular form is found and in this case the program responds with active
                    ofRect(x,y,20,20);
                    active = true;
                }
            }
        }
    }

    //clicks
    for (int x = width/4; x < width/4 + 20;x+=1) {
        for (int y = size; y < size+15;y+=1) {
            int degreesMade = 0;
            if (pixels[(y*width) + x] == NULL) {
                for (int a=0;a < 360; a+=30) {
                    int newX = cos(a) * size;
                    int newY = sin(a) * size;
                    if (pixels[((y+newY)*width) + x + newX] != NULL) {
                        degreesMade++;
                    }
                }
                if (degreesMade >= value/2) {
                    ofRect(x,y,20,20);
                    if (clickTimer >= 100) {
                        //in this case when a circular object is found it responds with a left mouse click
                        mouseCTRL.leftButtonClick();
                        clickTimer = 0;
                    }
                }
            }
        }
    }

    //checks for mousemover
    for (int x = size+width/2; x < width-size;x+=1) {
        for (int y = size; y < (height/2)-size;y+=1) {
            int degreesMade = 0;
            if (pixels[(y*width) + x] == NULL) {
                for (int a=0;a < 360; a+=30) {
                    int newX = cos(a) * size;
                    int newY = sin(a) * size;
                    if (pixels[((y+newY)*width) + x + newX] != NULL) {
                        degreesMade++;
                    }
                }
                if (degreesMade >= value && active == true) {
                    //and in this final case the mouse is moved to the desired position
                    ofRect(x,y,20,20);
                    //x is mirrored value of 210-290
                    //y is value of 25-85
                    int newX = 1280 - ((x-210) * (1280/80));
                    int newY = (y-25) * (768/60);
                    mouseCTRL.setCursorPosition(newX,newY);
                }
            }
        }
    }

    //output field
    ofSetColor(0xCCCCCC);
    ofTranslate(0,5+height);
    ofRect(0,0,200,50);
    ofSetColor(0x000000);
    verdana.drawString("(1-2),threshold: " + ofToString(threshold), 10,10);
	verdana.drawString("(3-4),size of Detection: " + ofToString(size), 10,22);
	verdana.drawString("(5-6),value of Recognition: " + ofToString(value), 10,34);
	verdana.drawString("(7-8),value of Blurring: " + ofToString(blur), 10,46);

    /*
	// then draw the contour field with margins
	ofFill();
	ofSetColor(0x333333);
	ofRect(360,540,320,240);
	//safezones
	ofSetColor(0x999999);
	ofRect(410,570,50,30);
	ofRect(580,570,50,30);
	ofRect(490,540,60,50);
	ofNoFill();
	ofRect(360,520,150,130);
	ofRect(530,520,150,130);

	ofSetColor(0xffffff);


	//every frame the vectors must be cleared
    leftX.clear();
    leftY.clear();
    rightX.clear();
    rightY.clear();
    midX.clear();
    midY.clear();

    //and other parameters must be reset
    leftB = false;
    rightB = false;
    midB = false;
    avgMidX = 0;
    avgMidY = 0;

    //the for loop creates new values for the vectors
    for (int i = 0; i < contourFinder.nBlobs; i++){
        //draws each blob
        contourFinder.blobs[i].draw(360,540);

        //for each blob, the coordinates of the blob are put into array
        int tempX = contourFinder.blobs[i].boundingRect.x + (contourFinder.blobs[i].boundingRect.width/2);
        int tempY = contourFinder.blobs[i].boundingRect.y + (contourFinder.blobs[i].boundingRect.height/2);

        //depending on the X coordinate, the array is devided into 3 groups, the head field (blue), and the hands (green and red)
        if (tempY < 100) {
            if (tempX <150) {
                leftX.push_back(tempX);
                leftY.push_back(tempY);
                leftB = true;
            }
            else if (tempX > 170){
                rightX.push_back(tempX);
                rightY.push_back(tempY);
                rightB = true;
            }
        }

        midX.push_back(tempX);
        midY.push_back(tempY);
        midB = true;
    }

    //the tracking only works when the head piece is triggered
    if (midB == true) {
        for (int i=0;i<midX.size();i++) {
            avgMidX+=midX[i];
            avgMidY+=midY[i];
        }
        avgMidX /= midX.size();
        avgMidY /= midY.size();

        ofFill();
        ofSetColor(0x0000FF);
        ofRect(360+avgMidX-25,540+avgMidY-25,50,50);


        //when the headpiece is on, the left hand checks its activity and then resets
        if (leftB == true) {
            timerLeft = 0;
            avgLeftX = 0;
            avgLeftY = 0;

            //when it has been tracked, the new coordinates are used to move the red field
            for (int i=0;i<leftX.size();i++) {
                if (leftY[i] < 100) {
                    avgLeftX+=leftX[i];
                    avgLeftY+=leftY[i];
                }
            }
            avgLeftX /= leftX.size();
            avgLeftY /= leftY.size();

            ofFill();
            ofSetColor(0xFF0000);
            ofRect(360+avgLeftX-25,540+avgLeftY-25,50,50);


        } else {
            //if it hasnt been tracked, a timer is called which waits 1 second before it stops showing the red field
            timerLeft++;
            if (timerLeft <= holdTime) {
                ofFill();
                ofSetColor(0xFF0000);
                if (avgLeftY < 100) {
                    if (avgLeftX < 40) {
                        if (leftClick == false) {
                            //mouseCTRL.leftButtonClick();
                            leftClick = true;
                        }
                    } else if (avgLeftX > 90) {
                        //mouseCTRL.rightButtonClick();
                    }
                    if (avgLeftY < 50) {
                        //ofSetColor(0xCC0000);
                    } else if (avgLeftY > 70) {
                        //ofSetColor(0x000000);
                    }
                }
                ofRect(360+avgLeftX-25,540+avgLeftY-25,50,50);


                //avgLeftX center is 70
            }
        }
        //the right hand works thesame, only in green
        if (rightB == true) {
            timerRight = 0;
            avgRightX = 0;
            avgRightY = 0;

            for (int i=0;i<rightX.size();i++) {
                if (rightY[i] < 100) {
                    avgRightX+=rightX[i];
                    avgRightY+=rightY[i];
                }
            }

            avgRightX /= rightX.size();
            avgRightY /= rightY.size();

            ofFill();
            ofSetColor(0x00FF00);
            ofRect(360+avgRightX-25,540+avgRightY-25,50,50);

            nMouseX = 1280 - int((avgRightX - 200) * 12.8);
            nMouseY = int((avgRightY - 20) * 8 * 1.25);
            //mouseCTRL.setCursorPosition(nMouseX,nMouseY);

            //avgRightX may varie 200 -> 300
            //avgRightY may varie 10 -> 90
        } else {
            timerRight++;
            if (timerRight <= holdTime) {
                ofFill();
                ofSetColor(0x00FF00);
                ofRect(360+avgRightX-25,540+avgRightY-25,50,50);
            }
        }
    }

	// finally, a report:

	ofSetColor(0xffffff);
	char reportStr[1024];
	sprintf(reportStr, "bg subtraction and blob detection\npress ' ' to capture bg\nthreshold %i (press: +/-)\nnum blobs found %i, fps: %f", threshold, size, ofGetFrameRate());
	ofDrawBitmapString(reportStr, 20, 600);

	if (leftClick == true) {
	    clickTimer++;
	    if (clickTimer >= 100) {
	        leftClick = false;
	    }
	}*/
}


//--------------------------------------------------------------
void testApp::keyPressed  (int key){

	switch (key){
		case ' ':
			bLearnBakground = true;
			break;
		case '1':
			threshold--;
			if (threshold > 255) threshold = 255;
			break;
		case '2':
			threshold++;
			if (threshold < 0) threshold = 0;
			break;
        case '3':
            size--;
            break;
        case '4':
            size++;
            break;
        case '5':
            value--;
            break;
        case '6':
            value++;
            break;
        case '7':
            blur--;
            break;
        case '8':
            blur++;
            break;

	}
}

//--------------------------------------------------------------
void testApp::mouseMoved(int x, int y ){
}

//--------------------------------------------------------------
void testApp::mouseDragged(int x, int y, int button){
}

//--------------------------------------------------------------
void testApp::mousePressed(int x, int y, int button){
}

//--------------------------------------------------------------
void testApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void testApp::windowResized(int w, int h){

}

